const state = {
    deviceId: '',
    serviceId: '080DE97C-83F9-B6DD-3E78-2636A4B9C6D6',
    characteristicId: 'FCA38AF3-B7BF-CC2F-74FF-C243F49191F7',
    events: {},
    callbacks: {},
    index: -1,
}
//event
const on = (name, fn) => {
    state.events[name] = fn
}
const off = (name) => {
    delete state.events[name]
}
const emit = (name, data) => {
    const fn = state.events[name]
    if (fn) fn(data)
}

const list2ab = (list) => {
    const size = list.length
    const ab = new ArrayBuffer(size)
    const dataview = new DataView(ab)
    for (let i = 0; i < size; i++) {
        dataview.setUint8(i, list[i])
    }
    return ab
}
const ab2list = (ab) => {
    const list = [], size = ab.byteLength
    const dataview = new DataView(ab)
    for (let i = 0; i < size; i++) {
        list[i] = dataview.getUint8(i)
    }
    return list
}
const writeList = (cmd, list) => {
    return new Promise((resolve, reject) => {
        const { deviceId, serviceId, characteristicId } = state
        state.index++;
        if (state.index > 255) {
            state.index = 0
        }
        state.callbacks[state.index] = ([_, code, ...data]) => {
            code ? reject({ code, msg: 'server error' }) : resolve(data)
        }
        const wrap = [state.index, cmd, ...list]
        wx.writeBLECharacteristicValue({ deviceId, serviceId, characteristicId, value: list2ab(wrap) })
        cmd ? emit('write', wrap) : emit('read', wrap)
    })
}
const read = (len) => {
    return writeList(0, [len])
}
const write = (list) => {
    return writeList(1, list)
}
const authorize = async () => {
    const { authSetting } = await wx.getSetting()
    if (!authSetting['scope.bluetooth']) {
        await wx.authorize({ scope: 'scope.bluetooth' })
    }
}
const open = async () => {
    return wx.openBluetoothAdapter({ mode: 'central' })
}
const found = () => {
    return wx.startBluetoothDevicesDiscovery({ allowDuplicatesKey: false })
}
const listen = () => {
    wx.onBluetoothDeviceFound(({ devices }) => {
        const { deviceId } = devices.find(o => o.name == 'TEF6686-BLE-Server') || {}
        if (deviceId) {
            state.deviceId = deviceId
            wx.stopBluetoothDevicesDiscovery()
            emit('found', true)
        } else {
            emit('found', false)
        }
    })
    wx.onBLEConnectionStateChange(({ deviceId, connected }) => {
        if (deviceId == state.deviceId) {
            emit('connect', connected)
        }
    })
    wx.onBLECharacteristicValueChange(res => {
        const { deviceId, serviceId, value } = res
        if (deviceId == state.deviceId && serviceId == state.serviceId) {
            const list = ab2list(value)
            const index = list[0]
            const callback = state.callbacks[index]
            if (callback) {
                delete state.callbacks[index]
                callback(list)
            }
            emit('notify', list)
        }
    })
}
const connect = (bool) => {
    const { deviceId } = state
    return bool ? wx.createBLEConnection({ deviceId }) : wx.closeBLEConnection({ deviceId })
}
const getServices = () => {
    const { deviceId } = state
    return wx.getBLEDeviceServices({ deviceId })
}
const getCharacteristics = () => {
    const { deviceId, serviceId } = state
    return wx.getBLEDeviceCharacteristics({ deviceId, serviceId })
}
const notify = async () => {
    const { deviceId, serviceId, characteristicId } = state
    await wx.notifyBLECharacteristicValueChange({ state: true, deviceId, serviceId, characteristicId })
}

const close = () => {
    wx.offBluetoothDeviceFound()
    wx.offBLECharacteristicValueChange()
    wx.offBLEConnectionStateChange()
    wx.closeBluetoothAdapter()
}

module.exports = {
    on,
    off,
    emit,
    authorize,
    open,
    close,
    found,
    connect,
    getServices,
    getCharacteristics,
    listen,
    notify,
    write,
    read,
}